package org.jeecg.modules.bpm.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.interceptor.Command;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StreamUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.bpm.model.diagram.HistoryProcessInstanceDiagramCmd;
import org.jeecg.modules.bpm.service.impl.ActProcessService;
import org.jeecg.modules.extbpm.process.entity.ExtActProcess;
import org.jeecg.modules.extbpm.process.service.IExtActProcessService;
import org.jeecg.modules.extbpm.util.CommonRandomUtil;
import org.jeecgframework.designer.vo.AjaxJson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * 流程管理功能
 * 
 * @author scott
 */
@Slf4j
@Api(tags="流程实例")
@RestController("actProcessController")
@RequestMapping("/act/process")
public class ActProcessController {

	@Autowired
	private RepositoryService repositoryService;
	@Autowired
	private ActProcessService actProcessService;
	@Autowired
	private IExtActProcessService extActProcessService;

	@Autowired
	private ISysBaseAPI sysBaseAPI;
	@Autowired
	@Lazy
	private RedisUtil redisUtil;
	/**
	  * 查询所有版本的流程
	 * @param params
	 * @return
	 */
	@GetMapping("list")
	public Result<IPage<Map<String, Object>>> list(@ApiIgnore @RequestParam Map<String, Object> params) {
		Result<IPage<Map<String, Object>>> result = new Result<IPage<Map<String, Object>>>();
		IPage<Map<String, Object>> pageList = new Page<Map<String, Object>>();
		List<Map<String, Object>> records = actProcessService.page(params);
		pageList.setRecords(records);
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}

	@PostMapping("deploy")
	@ApiOperation("部署流程文件")
	public Result deploy(@RequestParam("processFile") MultipartFile file) throws IOException {
		if (file.isEmpty()) {
			return Result.error("发布流程失败！");
		}

		try {
			actProcessService.deploy(file);
			return Result.ok("流程上传成功！");
		} catch (Exception e) {
			return Result.error("发布流程失败: "+ e.getMessage());
		}
	}

	/**
	  * 激活流程
	 * @param id
	 * @return
	 */
	@GetMapping("active/{id}")
	public Result active(@PathVariable("id") String id) {
		actProcessService.active(id);
		return new Result();
	}

	/**
	 * 挂起流程
	 * @param id
	 * @return
	 */
	@GetMapping("suspend/{id}")
	@ApiOperation("挂起流程")
	@ApiImplicitParam(name = "id", value = "流程ID", paramType = "query", dataType = "String")
	public Result suspend(@PathVariable("id") String id) {
		actProcessService.suspend(id);
		return new Result();
	}

	/**
	 * 转成模型
	 * @param id
	 * @return
	 * @throws Exception
	 */
	@GetMapping("convertToModel/{id}")
	public Result convertToModel(@PathVariable("id") String id) throws Exception {
		actProcessService.convertToModel(id);
		return new Result();
	}

	/**
	 * 删除
	 * @param deploymentIds
	 * @return
	 */
	@DeleteMapping(value = "/delete")
	public Result delete(@RequestParam(name = "ids", required = true) String ids) {
		if(CommonRandomUtil.isNotEmpty(ids)) {
			for (String id : Arrays.asList(ids.split(","))) {
				actProcessService.deleteDeployment(id);
			}
		}
		return new Result();
	}

	/**
	  * 显示静态资源（图片/XML）
	 * @param deploymentId
	 * @param resourceName
	 * @param response
	 * @throws Exception
	 */
	@GetMapping(value = "resource")
	@ApiImplicitParams({ @ApiImplicitParam(name = "deploymentId", value = "部署ID", paramType = "query", dataType = "String"),
	@ApiImplicitParam(name = "resourceName", value = "资源名称", paramType = "query", dataType = "String") })
	public void resource(@RequestParam(value="deploymentId")String deploymentId, @RequestParam(value="resourceName")String resourceName, @ApiIgnore HttpServletResponse response) throws Exception {
		log.debug("-------------deploymentId-----",deploymentId);
		log.debug("-------------resourceName-----",resourceName);
		InputStream resourceAsStream = actProcessService.getResourceAsStream(deploymentId, resourceName);
		IOUtils.copy(resourceAsStream, response.getOutputStream());
	}
	
	
	/**
	  * 获取流程进度图
	 * @param processInstanceId
	 * @param response
	 * @throws Exception
	 */
	@GetMapping(value = "processPic")
	@ApiImplicitParams({ @ApiImplicitParam(name = "processInstanceId", value = "流程实例ID", paramType = "query", dataType = "String")})
	public void processPic(@RequestParam(value="processInstanceId")String processInstanceId, HttpServletResponse response) throws Exception {
		Command<InputStream> cmd = new HistoryProcessInstanceDiagramCmd( processInstanceId);
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
		InputStream is = processEngine.getManagementService().executeCommand(cmd);
		IOUtils.copy(is, response.getOutputStream());
	}

	/**
	 * 读取资源，通过部署ID
	 *
	 * @param deploymentId 流程部署的ID
	 * @param resourceName 资源名称(foo.xml|foo.png)
	 * @param response
	 * @throws Exception
	 */
	@RequestMapping(value = "downProcessXml")
	public void downProcessXmlByDeploy(HttpServletRequest request, HttpServletResponse response) throws Exception {
		InputStream resourceAsStream = null;
		try {
			String deploymentId = oConvertUtils.getString(request.getParameter("deploymentId"));
			String resourceName = oConvertUtils.getString(request.getParameter("resourceName"));

			String token = oConvertUtils.getString(request.getParameter("token"));
			//校验 token 登录有效性
			TokenUtils.verifyToken(request, sysBaseAPI, redisUtil);

			resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
			// 文件下载
			File file = new File(resourceName);
			String filename = file.getName();
			// 设置response的Header
			response.setContentType("application/octet-stream");
			response.setHeader("Content-disposition", "attachment;filename="+ new String(filename.getBytes("utf-8"), "ISO8859-1"));
			IOUtils.copy(resourceAsStream, response.getOutputStream());
			response.flushBuffer();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (resourceAsStream != null) {
					resourceAsStream.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * @TODO 未实现
	 * 通过上传流程文件，发布流程
	 *
	 * @param deploymentId 流程部署的ID
	 * @param resourceName 资源名称(foo.xml|foo.png)
	 * @param response
	 * @throws Exception
	 */
	@RequestMapping(value = "deployProcess")
	@ResponseBody
	public void deployProcess(HttpServletRequest request) {
		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
		Map<String, MultipartFile> files = multipartRequest.getFileMap();

		List<String> urls = new ArrayList<>();
		for (Map.Entry<String, MultipartFile> entry : files.entrySet()) {
			MultipartFile file = entry.getValue();// 获取上传文件对象
			String fileName = file.getOriginalFilename();
			InputStream fileInputStream = null;
			try {
				fileInputStream = file.getInputStream();
				String extension = FilenameUtils.getExtension(fileName);
				if (extension.equals("zip") || extension.equals("bar")) {
					ZipInputStream zip = new ZipInputStream(fileInputStream);
					repositoryService.createDeployment().addZipInputStream(zip).deploy();
					zip.close();
				} else if (extension.equals("png")) {
					repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
				} else if (extension.indexOf("bpmn20.xml") != -1) {
					repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
				} else if (extension.equals("bpmn")) {
					/*
					 * bpmn扩展名特殊处理，转换为bpmn20.xml
					 */
					String baseName = FilenameUtils.getBaseName(fileName);
					repositoryService.createDeployment().addInputStream(baseName + ".bpmn20.xml", fileInputStream).deploy();
				} else {
					throw new ActivitiException("错误信息:不支改文件类型" + extension);
				}
			} catch (Exception e) {
				log.error("错误信息:在部署过程中,文件输入流异常" + e.toString());
			} finally {
				try {
					if (fileInputStream != null) {
						fileInputStream.close();
					}
				} catch (Exception e) {
				}
			}
		}
	}
}
